
package stratego.java.ssm;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import stratego.java.ssm.gui.GameCanvas;

/**
 * <code>public class Stratego implements ComponentListener</code>
 * <p>
 * Starts the main game windows, and is responsible for laying out all components, as well as
 * redirecting the output streams.
 * </p>
 * 
 * @author Mark Aligbe
 * 
 */
public class Stratego implements ComponentListener
{
	private JFrame	     frame;
	private final int	 size;
	private JDialog	     message;
	// The input area for the user.
	private JTextArea	 input;
	// The message output area. System.out is redirected to this
	private JTextArea	 textArea;
	/** This frame delay limits the FPS to 60 */
	public static double	FRAME_DELAY	= 50.0 / 3.0;
	private GameCanvas	 canvas;
	
	@SuppressWarnings("unused")
	public Stratego()
	{
		// Determine the full vertical size:
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		size = (int) screenSize.getHeight();
		// Set up the frame
		frame = new JFrame("Stratego");
		frame.setSize(size, size);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		// frame.setResizable(false);
		
		// Set up the message window
		message = new JDialog(frame);
		message.setTitle("Messages");
		message.setSize(size / 2, size * 2 / 3);
		message.setLocation(frame.getWidth(), 0);
		// Set up the message output
		textArea = new JTextArea();
		textArea.setEditable(false);
		textArea.setLineWrap(true);
		textArea.setWrapStyleWord(true);
		JScrollPane pane = new JScrollPane(textArea);
		pane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener()
		{
			String	lastText	= "";
			
			public void adjustmentValueChanged(AdjustmentEvent e)
			{
				if (textArea.getText().equals(lastText))
					return;
				lastText = textArea.getText();
				int length = textArea.getText().length();
				textArea.select(length, length);
			}
		});
		textArea.append(">>");
		// Setup the message input
		input = new JTextArea(3, 20);
		input.setLineWrap(true);
		input.setWrapStyleWord(true);
		JScrollPane inputPane = new JScrollPane(input);
		inputPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		inputPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		JPanel inputPanel = new JPanel(new GridBagLayout());
		// Set the global constraints
		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.BOTH;
		c.weightx = 0.5;
		// JLabel constraints
		c.gridheight = 1;
		c.gridwidth = 1;
		c.gridx = 0;
		c.gridy = 0;
		c.ipady = 10;
		inputPanel.add(new JLabel("Send:"), c);
		// InputPane constraints
		c.gridheight = 3;
		c.gridy = 1;
		inputPanel.add(inputPane, c);
		JPanel panel = new JPanel(new BorderLayout());
		panel.add(BorderLayout.CENTER, pane);
		panel.add(BorderLayout.SOUTH, inputPanel);
		message.getContentPane().add(panel);
		// Redirect that output streams
		redirectSystemStreams();
		
		// Add the window listeners
		frame.addComponentListener(this);
		message.addComponentListener(this);
		
		// Add the canvas
		canvas = new GameCanvas();
		frame.getContentPane().add(canvas);
		// Display the frame
		frame.setVisible(true);
		message.setVisible(true);
		
		// Show the splash screen
		int mode = splashScreen(frame);
		// Launch the appropriate game type
		if (mode == -1)
			System.exit(0);
		else if (mode == 0)
		{
			OnlineGame game = new OnlineGame(frame, canvas, input);
		}
		else
		{
			message.removeComponentListener(this);
			message.setVisible(false);
			OfflineGame game = new OfflineGame(frame, canvas);
		}
	}
	
	/**
	 * <code>private int splashScreen(JFrame frame)</code>
	 * <p>
	 * The splash screen for the Stratego Game. Displays a JOptionPane which greets the user and
	 * presents 2 mode choices
	 * </p>
	 * 
	 * @param frame
	 *            - The parent frame for the JOptionPane. Typically the main frame.
	 * @return An int representing the mode choice of the user. -1 Means the user closed the window,
	 *         0 means 2 player online, and 1 means 2 player offline.
	 */
	private int splashScreen(JFrame frame)
	{
		Object[] options =
		        {"<html><span style='font-size:12px;'>2 Player Online</span></html>",
		                "<html><span style='font-size:12px;'>2 Player Offline</span></html>"};
		String message =
		        "<html><center><span style='font-size:36px;'>" + "Computer Stratego"
		                + "</span><br/>" + "<span style='font-size:16px;'>" + "By:"
		                + "</span><br/><span style='font-size:16px;'>"
		                + "Sabina Smajlaj, Seth Aaron, and Mark Aligbe" + "</span></center></html>";
		return JOptionPane.showOptionDialog(frame, message, "Welcome", JOptionPane.DEFAULT_OPTION,
		        JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
	}
	
	/**
	 * <code>private void updateTextArea(final String text)</code>
	 * <p>
	 * Writes text to the Message box beside the main frame.
	 * </p>
	 * 
	 * @param text
	 *            - The String to write.
	 */
	private void updateTextArea(final String text)
	{
		SwingUtilities.invokeLater(new Runnable()
		{
			public void run()
			{
				textArea.append(text);
				if (text.contains("\n"))
					textArea.append(">>");
			}
		});
	}
	
	/**
	 * <code>private void redirectSystemStreams()</code>
	 * <p>
	 * Redirects the Standard Output Stream to the method updateTextArea, which appends text to the
	 * JTextArea textArea.
	 * </p>
	 */
	private void redirectSystemStreams()
	{
		OutputStream out = new OutputStream()
		{
			@Override
			public void write(int b) throws IOException
			{
				updateTextArea(String.valueOf((char) b));
			}
			
			@Override
			public void write(byte[] b, int off, int len) throws IOException
			{
				updateTextArea(new String(b, off, len));
			}
			
			@Override
			public void write(byte[] b) throws IOException
			{
				write(b, 0, b.length);
			}
		};
		
		System.setOut(new PrintStream(out, true));
		// System.setErr(new PrintStream(out, true));
	}
	
	@Override
	/**
	 * <code>public void componentHidden(ComponentEvent e)</code>
	 * <p>Prevents the message window from being closed, as there is no way to remove the JFrame buttons as of now.</p>
	 */
	public void componentHidden(ComponentEvent e)
	{
		((Component) e.getSource()).setVisible(true);
	}
	
	@Override
	/**
	 * <code>public void componentMoved(ComponentEvent e)</code>
	 * <p>Moves the message frame along with the main frame.</p>
	 */
	public void componentMoved(ComponentEvent e)
	{
		if (e.getSource() instanceof JFrame)
		{
			JFrame frame = (JFrame) e.getSource();
			if (frame.getTitle().equals("Stratego"))
			{
				Point p = frame.getLocation();
				message.setLocation((int) p.getX() + frame.getWidth(), (int) p.getY());
			}
		}
	}
	
	@Override
	public void componentResized(ComponentEvent e)
	{
		if (e.getSource() instanceof JFrame)
		{
			JFrame frame = (JFrame) e.getSource();
			if (frame.getTitle().equals("Stratego"))
			{
				Point p = frame.getLocation();
				message.setLocation((int) p.getX() + frame.getWidth(), (int) p.getY());
			}
		}
	}
	
	@Override
	public void componentShown(ComponentEvent e)
	{}
	
	@SuppressWarnings("unused")
	public static void main(String[] args)
	{
		// Change the look and feel of the application to the system default.
		try
		{
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		}
		catch (ClassNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (InstantiationException e)
		{
			e.printStackTrace();
		}
		catch (IllegalAccessException e)
		{
			e.printStackTrace();
		}
		catch (UnsupportedLookAndFeelException e)
		{
			e.printStackTrace();
		}
		Stratego stratego = new Stratego();
	}
}
